package com.yuyu.shop.domain.order.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuyu.commons.constant.EsIndexConstant;
import com.yuyu.commons.es.EsUtils;
import com.yuyu.commons.exception.BusinessException;
import com.yuyu.commons.security.LoginContext;
import com.yuyu.commons.security.LoginUser;
import com.yuyu.shop.api.apimodel.order.dto.QueryOrderByUserIdDTO;
import com.yuyu.shop.api.apimodel.order.es.ESOrderQueryDTO;
import com.yuyu.shop.api.apimodel.order.vo.OrderInfoVO;
import com.yuyu.shop.api.convert.OrderConvert;
import com.yuyu.shop.domain.order.DO.OrderDO;
import com.yuyu.shop.domain.order.repository.OrderRepository;
import com.yuyu.shop.infrastructure.persistence.po.OrderPO;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import org.elasticsearch.common.Strings;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author
 * @version 1.0
 * @description: 订单领域服务
 * @date 2022/8/17 14:29
 */
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
@Service
public class OrderDomainService {

    private final OrderRepository orderRepository;

    private final EsUtils esUtils;

    /**
     * 查询用户所有的订单(不论订单状态)
     * @param dto
     * @return
     */
    public Page<OrderInfoVO> queryOrderByUserId(QueryOrderByUserIdDTO dto){
        LoginUser user = LoginContext.getUser();
        if (Objects.isNull(user) || Objects.isNull(user.getUserId())){
            throw new BusinessException("用户登录失效,请稍候再试!");
        }
        Page<OrderDO> byUserId = orderRepository.getByUserId(user.getUserId(), dto.getType(), dto.getCurrent(), dto.getPageSize());
        List<OrderInfoVO> collect = byUserId.getRecords().stream().map(OrderConvert::orderDO2OrderInfoVO).collect(Collectors.toList());
        return (Page<OrderInfoVO>) new Page<OrderInfoVO>().setRecords(collect)
                .setCurrent(byUserId.getCurrent())
                .setSize(byUserId.getSize())
                .setTotal(byUserId.getTotal())
                .setPages(byUserId.getPages());
    }


    public IPage<OrderPO> queryESOrder(ESOrderQueryDTO dto){

        //Filter过滤器方式查询，它的查询不会计算相关性分值，也不会对结果进行排序,因此效率会高一点，查询的结果可以被缓存。 建议must都换成filter
        //构建sourceBuilder
        SearchSourceBuilder builder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        //构建查询条件 电话和订单号都不能分词
        if (StringUtil.isNotEmpty(dto.getPhone())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("phone.keyword", dto.getPhone()));
        }
        if (StringUtil.isNotEmpty(dto.getOrderId())){
        boolQueryBuilder.must(QueryBuilders.termQuery("orderId.keyword",dto.getOrderId()));
        }
        if (StringUtil.isNotEmpty(dto.getGoodsName())){
            //最低匹配精度，至少有[分词后的词语个数]x百分百，得出一个数据值取整。举个例子：当前属性设置为 70% ，
            // 若一个用户查询检 有10个词语，那么匹配度按照 10x70%=7，则goodsName中至少需要有7个词语匹配，就展示
            boolQueryBuilder.filter(QueryBuilders.wildcardQuery("goodsName",dto.getGoodsName() + "*"));
        }
        //模糊查询 并且boost权重查询 boost权重越大 排序越靠上 (商品名以及商标)
        BoolQueryBuilder searchCondition = new BoolQueryBuilder().should(QueryBuilders.wildcardQuery("goodsName", dto.getGoodsName() + "*").boost(2));
        searchCondition.should(QueryBuilders.wildcardQuery("label", dto.getGoodsName()).boost(5));
        boolQueryBuilder.must(searchCondition);
        if (Objects.nonNull(dto.getStatus())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("status",dto.getStatus()));
        }
        //查询时间范围
        //开始
        if (StringUtil.isNotEmpty(dto.getStartTime())) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime").from(dto.getStartTime()));
        }
        //结束
        if (StringUtil.isNotEmpty(dto.getEndTime())){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime").to(dto.getEndTime()));
        }
        boolQueryBuilder.must(QueryBuilders.multiMatchQuery(dto.getAddressOrUserName(),"address","userName"));
        //query_string和match类似，但是match需要指定字段名，query_string是在所有字段中搜索，范围更广泛。
        boolQueryBuilder.must(QueryBuilders.queryStringQuery(dto.getStatus().toString()));
        //价格小于100大于10的订单
        boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte("10").lte("100"));
        builder.query(boolQueryBuilder);
        //第一个参数:指定查询某些字段 第二个参数:指定排除那些字段
        builder.fetchSource((String[]) Arrays.asList("shopName","orderId","goodsName","createTime").toArray(), Strings.EMPTY_ARRAY);
        //降序排序
        builder.sort("createTime", SortOrder.DESC);
        //构建分页
        Page<OrderPO> page = new Page<OrderPO>().setCurrent(dto.getCurrent()).setSize(dto.getPageSize());
        return esUtils.searchListDate(page, OrderPO.class, EsIndexConstant.ORDER, builder);
    }
}
